package com.cskaoyan.day5;


import java.util.Arrays;
import java.util.Scanner;

/**
 * 数组是一个容器，可以用存放元素，存放数据。
 * 在实际开发中，工程中也会需要存放大量数据，这一般是通过数据库来实现的。
 * 数据 持久化存储 一般需要使用数据库 永久保存在硬盘上
 * 数据在使用时 是需要读取到内存中的 这时内存中也需要一个容器来装这些数据 Java中容器一般使用集合(数组很少直接使用)
 * <p>
 * 实际开发的基本需求就是基于数据库的，对数据进行增删改查，即"crud"
 * 也有很多中低级Java程序员自嘲自己为"crud工程师"。
 * <p>
 * 当然"crud"指的是：
 * c，create：新增数据/增加。
 * r，retrieve：检索数据/查询。
 * u，update：更新数据/修改。
 * d，delete ：删除数据/删除。
 * 我们现在还没有学习过数据库，但是不重要
 * 。现在我们使用数组这个容器，来模拟数据库，实现日常开发中最常见的"crud"操作。
 * <p>
 * 现在提出以下需求:
 * 使用一个String类型数组,来存放人的名字
 * 数组中一个String人名代表一条数据
 * 特别注意: 数组中人名是唯一的,不可重复的
 * <p>
 * 接下来根据以上数组,完成对人名的"增删改查"
 *
 * @author wuguidong@cskaoyan.onaliyun.com
 * @since 16:21
 */
public class StringArrCRUDDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 模拟数据库
        String[] names = new String[10];
        names[0] = "张三";
        names[1] = "李四";
        names[2] = "长风";
        names[3] = "蔡徐坤iKun";
        names[4] = "鹿晗";
        names[5] = "吴亦凡";
        // 现在数组中有六个正常的人名,还有四个是null,默认值
        // System.out.println(Arrays.toString(names));
        printRealNames(names);
        System.out.println("下面开始进行插入人名的操作,请键盘录入一个准备插入的人名:");
        String targetInsertName = sc.nextLine();
        switch (createName(names, targetInsertName)) {
            case 0:
                System.out.println("插入成功!现在的人名数组是:");
                printRealNames(names);
                break;
            case 1:
                System.out.println("插入失败,数组满了,没有位置了");
                printRealNames(names);
                break;
            case 2:
                System.out.println("插入失败,插入的人名重复了!");
                printRealNames(names);
                break;
        }

        System.out.println("下面开始进行删除人名的操作,请键盘录入一个准备删除的人名:");
        String delTargetName = sc.nextLine();
        if (deleteName(names, delTargetName)) {
            System.out.println("删除成功");
            printRealNames(names);
        } else {
            System.out.println("删除失败!未找到目标元素!");
            printRealNames(names);
        }

        System.out.println("下面开始进行更改人名的操作,请键盘录入一个准备更名的人名和即将修改成的人名:");
        String sourceName = sc.nextLine();
        String targetName = sc.nextLine();
        if (updateName(names, sourceName, targetName) == 0) {
            System.out.println("修改成功");
            printRealNames(names);
        } else {
            System.out.println("查无此人！");
        }

        System.out.println("下面开始进行查询人名的操作,请键盘录入一个准备查询的人名:");
        String name = sc.nextLine();
        int index = selectName(names, name);
        if (index >= 0) {
            System.out.println(name + "的下标是:" + index);
            printRealNames(names);
        } else {
            System.out.println("查无此人！");
        }
    }

    // 需求: 输出人名数组中的所有人名,不包括其中的null元素
    public static void printRealNames(String[] names) {
        System.out.print("[");
        for (String name : names) {
            if (name == null) {
                // null跳过,不打印
                continue;
            }
            System.out.print(name + ", ");
        }
        System.out.println("\b\b]");
    }

    // 增
    /*
        分析一下对人名数组插入一个新人名的操作
        首先要明确,数组的长度是不可变的
        所以这里的插入/新增,指的是找到一个null元素的位置,然后赋值
        所以插入其实是一个赋值的过程

        这个插入操作,插入的结果有几种可能?
            1.插入成功,当数组存在null元素的位置,以及插入的人名不重复时
            2.插入失败,人名重复了.
            3.插入失败,没有null元素的位置,数组满了
       对于该方法而言,它的操作结果有三种可能性,这个方法的返回值类型如何写呢?
            这时建议方法返回一个表示插入结果的状态码
            比如方法返回:
                0: 表示插入成功
                1: 表示插入失败,数组满了,没有位置了
                2: 表示插入失败,插入的人名已经存在了
            该方法的返回值类型是一个int类型
     */

    /**
     * 方法返回:
     * 0: 表示插入成功
     * 1: 表示插入失败,数组满了,没有位置了
     * 2: 表示插入失败,插入的人名已经存在了
     *
     * @param names  被插入人名的人名数组
     * @param target 被插入的人名
     * @return int 方法执行结果的状态码
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/07/07 16:38
     */
    public static int createName(String[] names, String target) {
        // 1.判断人名是否存在,存在就直接插入失败
        /*
            人名是一个String类型,对于String来说,如何判断两个字符串的内容是一样的呢?
            使用String类当中的equals方法
            语法: String对象(引用)/字符串常量.equals(String对象(引用)/字符串常量)
         */
        // 遍历names数组,然后逐一比较
        for (String name : names) {
            /*
                name元素有可能等于null
                所以在调用方法之前,要先if判断
                避免空指针异常
             */
            if (name == null) {
                // null元素没有必要去比较,直接continue跳过
                continue;
            }

            // 这里target是不会等于null的,所以调转位置,也能够避免空指针异常
            if (name.equals(target)) {
                // 说明人名重复了,插入肯定失败
                return 2;
            }
        }
        // 代码运行到这里,被插入的人名肯定是不重复,所以开始进行插入操作
        // 2.人名不存在,尝试进行插入操作,如果插入不成功,那么一定就是数组满了
        for (int i = 0; i < names.length; i++) {
            // 找到一个null的位置,开始进行插入(赋值)
            if (names[i] == null) {
                // 还有位置进行插入,赋值,插入成功
                names[i] = target;
                return 0;
            }
        }
        // 如果遍历完整个数组,都没有插入成功,只有一个原因,就是数组满了
        return 1;
        /*
        // 1.判断还有没有位置来进行插入,遍历names数组,看一看还有没有null元素的位置
        // flag表示是否有位置插入,false表示没有位置了
        boolean flag = false;
        for (String name : names) {
            if (name == null) {
                // 有位置插入
                flag = true;
                break;
            }
        }
        if (!flag) {
            // 没有位置了
            return 1;
        }
        */
    }

    // 删
    /*
        分析一下删除功能
        首先要明确,数组的长度是不可变的
        是没有办法直接在原数组上真正删除一个元素
        所以这里的删除 指的是用一个null元素赋值取代原先的字符串

        这里的删除,结果有几种可能性?
        两种:
            1.删除成功,找到了要删除的人名.
            2.删除失败,没找到目标人名.
        这种具有二元性结果的方法,返回值一般给布尔类型,于是规定:
            true: 表示删除成功
            false: 表示删除失败,未找到目标人名
     */

    /**
     * 方法返回:
     * true: 表示删除成功
     * false: 表示删除失败,未找到目标人名
     *
     * @param names  被删除人名的数组
     * @param target 被删除的目标人名
     * @return boolean
     * @author wuguidong@cskaoyan.onaliyun.com
     * @since 2022/07/07 17:44
     */
    public static boolean deleteName(String[] names, String target) {
        for (int i = 0; i < names.length; i++) {
            // 遍历查找目标人名
            if (target.equals(names[i])) {
                // 找到了,赋值为null,删除成功
                names[i] = null;
                return true;
            }
        }
        // 删除失败,未找到目标人名
        return false;
    }

    // 改查
    /*
     *
     * 0表示修改成功
     * 1表示修改失败
     *
     * */
    public static int updateName(String[] names, String sourceName, String targetName) {
        for (int i = 0; i < names.length; i++) {
            if (sourceName.equals(names[i])) {
                names[i] = targetName;
                return 0;
            }
        }
        return 1;
    }

    public static int selectName(String[] names, String sourceName) {
        for (int i = 0; i < names.length; i++) {
            if (sourceName.equals(names[i])) {
                return i;
            }
        }
        return -1;
    }
}